package com.example.wan1.bus;

import android.util.Log;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/***
 * 工具类
 */
final class Utils {

    private Utils() {
        throw new UnsupportedOperationException("u can't instantiate me...");
    }


    /**
     * 判断对象是否相等
     *
     * @param o1 对象1
     * @param o2 对象2
     * @return {@code true}: 相等<br>{@code false}: 不相等
     */
    public static boolean equals(Object o1, Object o2) {
        return o1 == o2 || (o1 != null && o1.equals(o2));
    }


    /**
     * Require the objects are not null.
     * 要求非null
     *
     * @param objects The object.
     * @throws NullPointerException if any object is null in objects
     */
    public static void requireNonNull(final Object... objects) {
        if (objects == null) throw new NullPointerException();
        for (Object object : objects) {
            if (object == null) throw new NullPointerException();
        }
    }

    /***
     * 从范式中获取类型类
     * @param callback RxBus回调
     * @param <T>
     * @return 类对象
     */
    public static <T> Class<T> getTypeClassFromParadigm(final RxBus.Callback<T> callback) {
        if (callback == null) return null;
        Type[] genericInterfaces = callback.getClass().getGenericInterfaces();

        Type type;
        if (genericInterfaces.length == 1) {
            type = genericInterfaces[0];
        } else {
            type = callback.getClass().getGenericSuperclass();
        }
        type = ((ParameterizedType) type).getActualTypeArguments()[0];
        while (type instanceof ParameterizedType) {
            type = ((ParameterizedType) type).getRawType();
        }

        String className = type.toString();
        if (className.startsWith("class ")) {
            className = className.substring(6);
        } else if (className.startsWith("interface ")) {
            className = className.substring(10);
        }
        try {
            //noinspection unchecked
            return (Class<T>) Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }


    /***
     * 从实体类中得到class
     * @param obj
     * @return
     */
    public static Class getClassFromObject(final Object obj) {
        //判空
        if (obj == null) return null;

        Class objClass = obj.getClass();
        //objClass.isAnonymousClass() 如果是匿名类则返回true
        //isSynthetic todo ??? 主要针对访问其它类中的private修饰的方法或者是变量，编译器所产生的一个方法
        if (objClass.isAnonymousClass() || objClass.isSynthetic()) {
            //getGenericInterfaces 返回实现接口信息的Type数组，包含泛型信息
            Type[] genericInterfaces = objClass.getGenericInterfaces();
            //类或者是接口
            String className;

            if (genericInterfaces.length == 1) {// interface

                Type type = genericInterfaces[0];
                //ParameterizedType 参数化类型
                while (type instanceof ParameterizedType) {
                    type = ((ParameterizedType) type).getRawType();
                }
                className = type.toString();
            } else {// abstract class or lambda
                Type type = objClass.getGenericSuperclass();
                while (type instanceof ParameterizedType) {
                    type = ((ParameterizedType) type).getRawType();
                }
                className = type.toString();
            }

            Log.e("RxBus", className);
            //开头是class或者是interface分别获取对应的数据
            //疑惑？为什么每个类型后面都戴着空格？
            //todo 猜想：是上面的数据造成的？默认数据一直到空格前都是一致的吗？是的
            if (className.startsWith("class ")) {
                className = className.substring(6);
            } else if (className.startsWith("interface ")) {
                className = className.substring(10);
            }
            try {
                //加载class对象
                return Class.forName(className);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return objClass;
    }


    public static void logW(String msg) {
        Log.w("RxBus", msg);
    }


    public static void logE(String msg) {
        Log.e("RxBus", msg);
    }

}